#ifndef __tenacitas_interlace_text_core__coordinate__h__
#define __tenacitas_interlace_text_core__coordinate__h__


/** @file */


/** @todo */

// ==> C++ Headers
#include <limits>
#include <cstdint>

// ==> 3rds Headers

// ==> Our Headers
#include <tenacitas.return_code.core/rc.h>

// ==> Namespaces
using namespace std;

// ==> Macro Constants

// ==> Macro Commands


/** ==> namespace of the organization */
namespace tenacitas {
    /** ==> namespace for the project */
    namespace interlace_text {
        /** ==> bussiness, core, displaying, interacting, transmitting,
            storing */ 
        namespace core {

            // ==> Typedefs 

            // ==> Attributes 

            // ==> Functions

            // ==> Classes


            /** 
               @tparam supplier must define @p text and @p interlace

               @tparam supplier::text must define @p text, which is the type of
               string to be used: @p std::string, or @p std::wstring, or @p
               std::u16string, or @p std::u32string.

               @tparam supplier::interlace is the algorithm used to interlace the
               texts 

               @nosubgrouping 
            */
            template <typename supplier>
            class coordinate {

            public:
                // ==> coordinate - Public Types

                /** */
                typedef typename supplier::text text;

                /** */
                typedef typename text::value_type letter;

                /** */
                typedef int16_t position;

                // ==> coordinate - Friends
                    
                /** Class allowed to access private members of @p coordinate,
                    in order to perform tests */
                friend class coordinate_tester;

                /** */
                friend class supplier::interlace;

                /** */
                friend std::ostream & operator << (std::ostream & p_out,
                                                   const coordinate & p_coord) {
                    p_out << "[(" << p_coord.m_line << ","
                          << p_coord.m_column << "),"
                          << p_coord.m_letter << "]";

                    return p_out;
                }
                    

                // ==> coordinate - Public Constructors

                /** */
                inline coordinate() ;

                /** */
                inline coordinate(const position & p_line, 
                                  const position & p_column,
                                  const letter & p_letter) noexcept;

                /** */
                inline coordinate(const coordinate &) noexcept;

                /** */
                inline coordinate(coordinate &&) noexcept;

                /** Destructor */
                inline ~coordinate();

                // ==> coordinate - Public Accessors

                /** */
                inline bool is_positioned() const noexcept;

                /** */
                inline void unposition() noexcept;

                /** */
                inline const position & get_line() const noexcept;

                /** */
                inline const position & get_column() const noexcept;

                /** */
                inline const letter & get_letter() const noexcept;
                
                /** */
                inline void set_line(const position &) noexcept;

                /** */
                inline void set_column(const position &) noexcept;

                /** */
                inline void set_letter(const letter &) noexcept;
                    
                // ==> coordinate - Public Operators

                /** */
                inline coordinate & operator=(const coordinate &) noexcept; 

                /** */
                inline coordinate & operator=(coordinate &&) noexcept;

                /** not allowed */
                inline bool operator ==(const coordinate &) const noexcept;

                /** not allowed */
                inline bool operator !=(const coordinate &) const noexcept;

                /** not allowed */
                void* operator new (std::size_t size)
                    throw (std::bad_alloc) = delete; 

                /** not allowed */
                void operator delete (void *p_class_id) = delete;

                /** not allowed */
                void *operator new[] (size_t) = delete;

                /** not allowed */
                void operator delete[] (void *) = delete;

                // ==> coordinate - Public Attributes

                /** */
                static const letter invalid_letter;

                /** **/
                static const position invalid_position;

                static const class_id id = 14325799798169ULL;
                
            private:

                // ==> coordinate - Private Attributes

                /** */
                position m_line;

                /** */
                position m_column;

                /** */
                letter m_letter;


                
            };
        }
    }
}

// =============================================================================
// I M P L E M E N T A T I O N
// =============================================================================

using namespace tenacitas::interlace_text::core;

// coordinate #################################################################

// -----------------------------------------------------------------------------
template<typename supplier>
const typename coordinate<supplier>::letter
coordinate<supplier>::
invalid_letter(std::char_traits<letter>::to_char_type
             (std::char_traits<letter>::eof()) );

// -----------------------------------------------------------------------------
template<typename supplier>
const typename coordinate<supplier>::position
coordinate<supplier>::
invalid_position(std::numeric_limits<position>::lowest());

// -----------------------------------------------------------------------------
template<typename supplier>
const class_id
coordinate<supplier>::
id;

// -----------------------------------------------------------------------------
template<typename supplier>
coordinate<supplier>::
coordinate()
    : m_line(invalid_position),
      m_column(invalid_position),
      m_letter(invalid_letter) {}

// -----------------------------------------------------------------------------
template<typename supplier>
coordinate<supplier>::
coordinate(const position & p_line,
           const position & p_column,
           const letter & p_letter) noexcept
    : m_line(p_line),
      m_column(p_column),
      m_letter(p_letter) {}

// -----------------------------------------------------------------------------
template<typename supplier>
coordinate<supplier>::
coordinate(const coordinate & p_coord) noexcept
    : m_line(p_coord.m_line),
      m_column(p_coord.m_column),
      m_letter(p_coord.m_letter) {}

// -----------------------------------------------------------------------------
template<typename supplier>
coordinate<supplier>::
coordinate(coordinate && p_coord) noexcept {
    m_line = std::move(p_coord.m_line);
    m_column = std::move(p_coord.m_column);
    m_letter = std::move(p_coord.m_letter);
}

// -----------------------------------------------------------------------------
template<typename supplier>
coordinate<supplier>::
~coordinate() {}

// -----------------------------------------------------------------------------
template<typename supplier>
const typename coordinate<supplier>::position &
coordinate<supplier>::
get_line() const noexcept {return m_line;}

// -----------------------------------------------------------------------------
template<typename supplier>
const typename coordinate<supplier>::position &
coordinate<supplier>::
get_column() const noexcept {return m_column;}

// -----------------------------------------------------------------------------
template<typename supplier>
const typename coordinate<supplier>::letter & 
coordinate<supplier>::
get_letter() const noexcept {return m_letter;}

// -----------------------------------------------------------------------------
template<typename supplier>
void
coordinate<supplier>::
set_line(const position & p_value) noexcept {
    m_line = p_value;
}

// -----------------------------------------------------------------------------
template<typename supplier>
void
coordinate<supplier>::
set_column(const position & p_value) noexcept {
    m_column = p_value;
}

// -----------------------------------------------------------------------------
template<typename supplier>
void
coordinate<supplier>::
set_letter(const letter & p_letter) noexcept {
    m_letter = p_letter;
}

// -----------------------------------------------------------------------------
template<typename supplier>
bool
coordinate<supplier>::
is_positioned() const noexcept {
    return (
        (m_line != std::numeric_limits<coordinate::position>::lowest())
        &&
        (m_column != std::numeric_limits<coordinate::position>::lowest())
        );
}

/** */
// -----------------------------------------------------------------------------
template<typename supplier>
void
coordinate<supplier>::
unposition() noexcept {
    m_line = invalid_position;
    m_column = invalid_position;
}


// -----------------------------------------------------------------------------
template<typename supplier>
typename coordinate<supplier>::coordinate &
coordinate<supplier>::
operator=(const coordinate & p_coord) noexcept {
    if (this != &p_coord) {
        m_line = p_coord.m_line;
        m_column = p_coord.m_column;
        m_letter = p_coord.m_letter;        
    }
    return *this;
}

// -----------------------------------------------------------------------------
template<typename supplier>
typename coordinate<supplier>::coordinate &
coordinate<supplier>::
operator=(coordinate && p_coord) noexcept {
    if (this != &p_coord) {
        m_line = std::move(p_coord.m_line);
        m_column = std::move(p_coord.m_column);
        m_letter = std::move(p_coord.m_letter);
    }
    return *this;
}

// -----------------------------------------------------------------------------
template<typename supplier>
bool
coordinate<supplier>::
operator ==(const coordinate & p_coord) const noexcept {
    return ( (m_line == p_coord.m_line) &&
             (m_column == p_coord.m_column) && 
             (m_letter == p_coord.m_letter) ) ;
}

// -----------------------------------------------------------------------------
template<typename supplier>
bool
coordinate<supplier>::
operator !=(const coordinate & p_coord) const noexcept {
    return (!(*this == p_coord));
}

#endif
